package name.weily.liba.tools

import android.content.Context
import android.content.SharedPreferences
import androidx.annotation.NonNull

class SharedPrefUtil private constructor(@NonNull cxt: Context, name: String = "") {

    companion object {
        private var instance: SharedPrefUtil? = null

        fun get(name: String = "sharedPreferences"): SharedPrefUtil = instance
            ?: synchronized(SharedPrefUtil::class.java) {
            return@synchronized instance
                ?: SharedPrefUtil(ContextProvider.getAppCxt(), name).apply {
                instance = this
            }
        }
    }

    private var sharedPreferences: SharedPreferences = cxt.getSharedPreferences(name, Context.MODE_PRIVATE)


    fun getInt(key: String, defaultValue: Int) = sharedPreferences.runSync { getInt(key, defaultValue) }
    fun getFloat(key: String, defaultValue: Float) = sharedPreferences.runSync { getFloat(key, defaultValue) }
    fun getLong(key: String, defaultValue: Long) = sharedPreferences.runSync { getLong(key, defaultValue) }
    fun getString(key: String, defaultValue: String?) = sharedPreferences.runSync { getString(key, defaultValue) }
    fun getStringSet(key: String, defaultValue: MutableSet<String>? = mutableSetOf<String>()) = sharedPreferences.runSync { getStringSet(key, defaultValue) }
    fun getBoolean(key: String, defaultValue: Boolean) = sharedPreferences.runSync { getBoolean(key, defaultValue) }

    /**
     * @param value should be one of these types:
     * [Int], [Long], [Float], [String], [Boolean]
     */
    fun <T: Any> put(key: String, value: T?, async: Boolean = false) : Boolean {
        return sharedPreferences.runSync {
            this.edit().apply {
                when (value) {
                    is Int -> { putInt(key, value) }
                    is Long -> { putLong(key, value) }
                    is Float -> { putFloat(key, value) }
                    is String -> { putString(key, value) }
                    is Boolean -> { putBoolean(key, value) }
                }
            }.let { if (async) { it.apply(); true } else it.commit() }
        }
    }

    fun putStringSet(key: String, value: MutableSet<String>?, async: Boolean = false) : Boolean {
        return sharedPreferences.runSync {
            edit().putStringSet(key, value).let { if (async) { it.apply();true } else it.commit() }
        }
    }

    fun remove(key: String) {
        sharedPreferences.runSync { this.edit().remove(key).commit() }
    }

    fun clear() {
        sharedPreferences.runSync { this.edit().clear().commit() }
    }

    fun addSharedPreferenceChangeListener(@NonNull listener: SharedPreferences.OnSharedPreferenceChangeListener) {
        sharedPreferences.runSync { registerOnSharedPreferenceChangeListener(listener) }
    }

    fun removeSharedPreferenceChangeListener(@NonNull listener: SharedPreferences.OnSharedPreferenceChangeListener) {
        sharedPreferences.runSync { unregisterOnSharedPreferenceChangeListener(listener) }
    }

}